package controllers

import (
	"TeacherManager/models"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"TeacherManager/common"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/json"
	//"time"
	"TeacherManager/system"
)

/**
* Created by LONG  on 2018/5/28.
 */
type ExamRespBody struct {
	ExamId    int                  `json:"examid"`
	Questions []common.Expresstion `json:"questions"`
}

func SaveExam(c *gin.Context) {
	var err error
	var reqInfo ExamRespBody
	err = c.BindJSON(&reqInfo)
	//examid := c.PostForm("examid")
	//test := c.PostForm("questions")
	//questions := c.PostFormArray("questions")
	//eid := common.String_2_int(examid)
	//fmt.Println(reqInfo, test, questions, eid)
	exam := &models.Exam{
		ExamID: uint(reqInfo.ExamId),
	}
	exam.GetExamByID()
	classmsgs, _ := exam.GetClassByExamId()
	classid := classmsgs[0].ID
	//msgbyte :=[]byte(exam.Title)
	//newmsg := common.ConvertByte2String(msgbyte, common.UTF8)

	err = common.UpdateExamQuestions(reqInfo.ExamId, reqInfo.Questions)
	msg := fmt.Sprintf("%s#%d#%s", "save", classid, exam.Title)
	fmt.Printf("%s",msg)
	common.Publish(msg)

	if err == nil {
		c.JSON(http.StatusOK, gin.H{
			"succeed": true,
			"message": "修改成功",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"succeed": true,
			"message": "数据库异常 操作失败",
		})
		return
	}
}

//学生查看题目 需要查看进行已经发布检验
func ExamGetByStu(c *gin.Context) {
	//id := c.Param("id")
	//page, err := models.GetPageById(id)
	//if err == nil && page.IsPublished {
	//	page.View++
	//	page.UpdateView()
	//	c.HTML(http.StatusOK, "page/display.html", gin.H{
	//		"page": page,
	//	})
	//} else {
	//	Handle404(c)
	//}
}

//教师端查看题目
func ExamGetByTeacher(c *gin.Context) {
	id := c.Param("id")
	eid := common.String_2_int(id)
	user, _ := c.Get(CONTEXT_USER_KEY)
	exam := &models.Exam{
		ExamID: uint(eid),
	}
	exam.GetExamByID()
	examquestions, err := common.GetExamQuestionsByExamId(eid)
	if err == nil {
		c.HTML(http.StatusOK, "admin/display.html", gin.H{
			"user":      user,
			"comments":  models.MustListUnreadComment(),
			"questions": examquestions.Questions,
			"exam":      exam,
		})
	} else {
		Handle404(c)
	}
}

func getDegreeName(val *models.Exam) {
	switch val.Degree {
	case -1:
		val.DegreeName = "自定义"
	case 0:
		val.DegreeName = "简单"
	case 1:
		val.DegreeName = "中等"
	case 2:
		val.DegreeName = "困难"
	default:
		val.DegreeName = "未知"
	}
}

func UnpublishExam(c *gin.Context) {
	examid := c.PostForm("examid")
	eid := common.String_2_int(examid)
	err := models.UnpublishExam(eid)
	if err == nil {
		c.JSON(http.StatusOK, gin.H{
			"succeed": true,
			"message": "操作成功",
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"succeed": true,
			"message": "数据库异常 操作失败",
		})
		return
	}
}

func UpdateExam(c *gin.Context) {
	var flag = false
	var err error
	examname := c.PostForm("examname")
	examdescrib := c.PostForm("examdescrib")
	timerange := c.PostForm("timerange")
	cid := common.String_2_int(c.PostForm("cid"))
	examdescrib = strings.TrimSpace(examdescrib)
	examname = strings.TrimSpace(examname)
	exam := &models.Exam{
		ExamID:  uint(cid),
		Title:   examname,
		DesCrib: examdescrib,
	}

	pubclass := c.PostForm("pubclass")
	pubclass_split := strings.Split(pubclass, ",")
	fmt.Println(pubclass_split)
	if len(pubclass_split) != 0 {
		err = models.InsertExamWithClass(pubclass_split, exam.ExamID)
	}
	if len(timerange) != 0 {
		temtime := strings.TrimSpace(timerange)
		split := strings.Split(temtime, " ")
		StartTime := fmt.Sprintf("%s %s", split[0], split[1])
		EndTime := fmt.Sprintf("%s %s", split[3], split[4])
		//myStartTime, err = time.Parse("2006-01-02 03:04", StartTime)
		//myEndTime, err = time.Parse("2006-01-02 03:04", EndTime)
		exam.StartTime = StartTime
		exam.EndTime = EndTime
		exam.IsPublished = true
		go func() {
			msg := fmt.Sprintf("%s#%s#%s", "add", pubclass, exam.Title)
			common.Publish(msg)
		}()

		flag = true
	}

	if len(exam.Title) == 0 {
		err = errors.New("测试名称都不能为空")
	} else {

		err = exam.UpdateExam(flag)
		if err == nil {
			c.JSON(http.StatusOK, gin.H{
				"succeed": true,
				"message": "更改成功",
				"exam":    exam,
			})
			return
		} else {
			err = errors.New(" 数据库异常 更改失败")
		}
	}
	c.JSON(http.StatusOK, gin.H{
		"succeed": false,
		"message": err.Error(),
	})
}
func ManagerExam(c *gin.Context) {
	user, _ := c.Get(CONTEXT_USER_KEY)
	u, _ := user.(*models.User)
	publishexams, _ := models.ListAllPubExam(u.ID)
	unpublishexams, _ := models.ListAllUnPubExam(u.ID)
	for _, val := range publishexams {
		getDegreeName(val)
	}
	for _, val := range unpublishexams {
		getDegreeName(val)
	}
	c.HTML(http.StatusOK, "admin/managerexams.html", gin.H{
		"user":           user,
		"comments":       models.MustListUnreadComment(),
		"publishexams":   publishexams,
		"unpublishexams": unpublishexams,
	})
}
func GetExams(c *gin.Context) {
	//time.Sleep(2 * time.Second);
	user, _ := c.Get(CONTEXT_USER_KEY)
	u, _ := user.(*models.User)
	publishexams, _ := models.ListAllPubExam(u.ID)
	unpublishexams, _ := models.ListAllUnPubExam(u.ID)

	for _, val := range publishexams {
		if len([]rune(val.DesCrib)) > 10 {
			val.DesCrib = fmt.Sprintf("%s....", string([]rune(val.DesCrib)[:10]))
		}
	}
	for _, val := range unpublishexams {
		if len([]rune(val.DesCrib)) > 10 {
			val.DesCrib = fmt.Sprintf("%s....", string([]rune(val.DesCrib)[:10]))
		}
	}
	c.HTML(http.StatusOK, "admin/seeexams.html", gin.H{
		"user":           user,
		"comments":       models.MustListUnreadComment(),
		"publishexams":   publishexams,
		"unpublishexams": unpublishexams,
	})
}

func DeleteExam(c *gin.Context) {
	examid := c.PostForm("examid")
	var ispublish bool = false
	pid, err := strconv.ParseUint(examid, 10, 64)
	if err == nil {
		exam := &models.Exam{}
		exam.ExamID = uint(pid)
		err = exam.GetCreateTimeById()
		ispublish = exam.IsPublished
		err = common.DeleteFile(int(exam.ExamID), exam.CreatedAt)
		//让班级测试数目减一
		exam.UpdateClassExamNums()
		err = exam.DeleteExam()
		if err == nil {
			c.JSON(http.StatusOK, gin.H{
				"succeed":   true,
				"message":   "删除成功",
				"ispublish": ispublish,
			})
			return
		}
	}
	c.AbortWithError(http.StatusInternalServerError, err)
}

func getConfigByDegree(degree int, exam *models.Exam) {
	var add_sub, mul_div, fraction, pt bool = false, false, false, false
	var calnums int
	var calcsim int
	var quesnums int
	switch degree {
	case 0:
		fmt.Println("1")
		add_sub = true
		quesnums = 30
		calnums = 10
		calcsim = 3
	case 1:
		fmt.Println("2")
		add_sub = true
		mul_div = true
		quesnums = 30
		calnums = 100
		calcsim = 3
	case 2:
		fmt.Println("3")
		add_sub = true
		mul_div = true
		fraction = true
		pt = true
		quesnums = 30
		calnums = 100
		calcsim = 3
	default:
		fmt.Println("未知配置")
	}
	exam.Add_Sub = add_sub
	exam.Mul_Div = mul_div
	exam.Fraction = fraction
	exam.Pt = pt
	exam.CalNums = calnums
	exam.MaxNumOfOper = calcsim
	exam.QuesNums = quesnums
}

func AutoExam(c *gin.Context) {
	var err error
	testname := c.PostForm("testname")
	pubclass := c.PostForm("pubclass")
	pubclass_split := strings.Split(pubclass, ",")
	fmt.Println(pubclass_split)
	testdescri := c.PostForm("testdescri")
	degree, _ := strconv.Atoi(c.PostForm("degree"))
	add_sub := c.PostForm("add_sub")
	mul_div := c.PostForm("mul_div")
	fraction := c.PostForm("fraction")
	pt := c.PostForm("pt")
	calcsim := c.PostForm("calcsim")
	calnums := c.PostForm("calnums")
	quesnums := c.PostForm("quesnums")
	mytime := c.PostForm("time")
	var ispublish bool
	fmt.Println(degree, add_sub, mul_div, fraction, pt, calcsim, calnums, quesnums, mytime)
	var teacherid uint
	user, _ := c.Get(CONTEXT_USER_KEY)
	if user != nil {
		u, ok := user.(*models.User)
		if ok && u.IsAdmin {
			teacherid = u.ID
		}

	}

	exam := &models.Exam{
		Title:     testname,
		TeacherID: teacherid,
		Degree:    degree,
	}

	if degree >= 0 {
		getConfigByDegree(degree, exam)
	} else {
		exam.Add_Sub = common.String_2_Bool(add_sub)
		exam.Mul_Div = common.String_2_Bool(mul_div)
		exam.Fraction = common.String_2_Bool(fraction)
		exam.Pt = common.String_2_Bool(pt)
		exam.CalNums = common.String_2_int(calnums)
		exam.MaxNumOfOper = common.String_2_int(calcsim)
		exam.QuesNums = common.String_2_int(quesnums)
	}

	if len(mytime) != 0 {
		ispublish = true
		temtime := strings.TrimSpace(mytime)
		split := strings.Split(temtime, " ")
		StartTime := fmt.Sprintf("%s %s", split[0], split[1])
		EndTime := fmt.Sprintf("%s %s", split[3], split[4])
		//myStartTime, err = time.Parse("2006-01-02 03:04", StartTime)
		//myEndTime, err = time.Parse("2006-01-02 03:04", EndTime)
		exam.StartTime = StartTime
		exam.EndTime = EndTime
		exam.IsPublished = true
	} else {
		exam.IsPublished = false
	}

	if len(strings.TrimSpace(testdescri)) != 0 {
		exam.DesCrib = testdescri
	}

	if len(exam.Title) == 0 {
		err = errors.New("测试名称不能为空")
	} else {
		var con = &common.Config{
			NumOfExp:       exam.QuesNums,
			Myrange:        exam.CalNums,
			MaxNumOfOper:   exam.MaxNumOfOper,
			HasFraction:    exam.Fraction,
			HasMulAndDiv:   exam.Mul_Div,
			HasParentheses: exam.Pt,
		}
		flag := make(chan bool)
		var result *common.Result
		go func() {
			result, err = common.GetExpresstions(con)
			flag <- true
		}()
		<-flag
		//result, err := common.GetExpresstions(con)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"succeed": false,
				"message": err.Error(),
			})
			return
		}
		resbytes, _ := json.Marshal(result)

		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"succeed": false,
				"message": err.Error(),
			})
			return
		}

		err = exam.Insert()
		var examid uint
		err, examid = exam.GetLastExamID()
		if ispublish && len(pubclass_split) != 0 {
			err = models.InsertExamWithClass(pubclass_split, examid)
		}

		//生成1000到题目
		//文件io很慢 如果用阻塞的的写法
		//用户就会卡3s才有成功提示
		//但是做出异步的话
		//有个问题。我拿不到写文件时候如果出错的信息。
		//TODO
		//解决上述问题
		//flag2 := make(chan bool)、
		//根据配置文件判断是写入mongo还是文件里
		if strings.Compare(system.GetConfiguration().Storage, "1") == 0 {
			//	存储到mongo中
			var tem = common.ExamQuestions{
				ExamID:    int(examid),
				Questions: result.Questions,
				QNums:     len(result.Questions),
			}
			err = common.AddExamQuestions(tem)
		} else {
			go func() {
				err = common.WriteFile(int(examid), resbytes)
				//flag2 <- true
			}()
		}

		//<-flag2
		if err == nil {

			if exam.IsPublished {
				go func() {
					msg := fmt.Sprintf("%s#%s#%s", "add", pubclass, exam.Title)
					common.Publish(msg)
				}()
			}

			c.JSON(http.StatusOK, gin.H{
				"succeed": true,
				"message": "建立成功",
				"exam":    exam,
			})
			return
		} else {
			err = errors.New("数据库异常")
		}
	}
	c.JSON(http.StatusOK, gin.H{
		"succeed": false,
		"message": err.Error(),
	})
}
